/*

 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2016年10月20日
 * <修改描述:>
 */
package com.tx.core.ddlutil.executor;

import com.tx.core.TxConstants;
import com.tx.core.ddlutil.builder.alter.AlterTableDDLBuilder;
import com.tx.core.ddlutil.builder.alter.AlterTableDDLBuilderFactoryRegistry;
import com.tx.core.ddlutil.builder.create.CreateTableDDLBuilder;
import com.tx.core.ddlutil.builder.create.CreateTableDDLBuilderFactoryRegistry;
import com.tx.core.ddlutil.model.*;
import com.tx.core.exceptions.SILException;
import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.util.MessageUtils;
import com.tx.core.util.SqlUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.PropertyPlaceholderHelper;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * Mysql 表相关 DDL执行器<br/>
 * <功能详细描述>
 *
 * @author  Administrator
 * @version  [版本号, 2016年10月20日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public abstract class AbstractTableDDLExecutor
        implements TableDDLExecutor, InitializingBean {

    //日志记录器
    protected Logger logger = LoggerFactory.getLogger(TableDDLExecutor.class);

    //DROP表
    private static final String SQL_DROP_TABLE = "DROP TABLE ${tableName};";

    //BACKUP表
    private static final String SQL_BACKUP_TABLE = "CREATE TABLE ${backupTableName} AS SELECT * FROM ${tableName};";

    private static PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper(
            "${", "}");

    /** dataSource句柄 */
    private DataSource dataSource;

    /** jdbcTemplate句柄 */
    private JdbcTemplate jdbcTemplate;

    /** schema */
    private String catalog;

    /** <默认构造函数> */
    public AbstractTableDDLExecutor(DataSource dataSource) {
        super();
        this.dataSource = dataSource;
    }

    /** <默认构造函数> */
    public AbstractTableDDLExecutor() {
        super();
    }

    /**
     * @throws Exception
     */
    @Override
    public final void afterPropertiesSet(){
        AssertUtils.notNull(this.dataSource ,"dataSource is null.");
        this.jdbcTemplate = new JdbcTemplate(this.dataSource);
        this.jdbcTemplate.afterPropertiesSet();

        try (Connection conn = this.dataSource.getConnection();){
            this.catalog = conn.getCatalog();
            AssertUtils.notEmpty(this.catalog, "catalog is empty.");
        } catch (SQLException e) {
            throw new SILException("dataSource.getConnection exception.", e);
        }

        //子类初始化
        init();
    }

    /**
      * 初始化表<br/>
      * <功能详细描述> [参数说明]
      *
      * @return void [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    protected void init() {

    }

    /**
     * 生成创建表的Builder对象<br/>
     * <功能详细描述>
     * @param tableName
     * @return [参数说明]
     *
     * @return CreateTableDDLBuilder [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Override
    public CreateTableDDLBuilder generateCreateTableDDLBuilder(
            String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");

        CreateTableDDLBuilder builder = CreateTableDDLBuilderFactoryRegistry
                .getFactory(getDatabaseType())
                .newInstance(tableName);
        return builder;
    }

    /**
     * @param table
     * @return
     */
    @Override
    public CreateTableDDLBuilder generateCreateTableDDLBuilder(TableDef table) {
        AssertUtils.notNull(table, "table is null.");
        AssertUtils.notEmpty(table.getName(), "table.tableName is empty.");

        CreateTableDDLBuilder builder = CreateTableDDLBuilderFactoryRegistry
                .getFactory(getDatabaseType())
                .newInstance(table);
        return builder;
    }

    /**
     * 生成修改表的Builder对象<br/>
     * <功能详细描述>
     * @param tableName
     * @return [参数说明]
     *
     * @return CreateTableDDLBuilder [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Override
    public AlterTableDDLBuilder generateAlterTableDDLBuilder(String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");
        AssertUtils.isTrue(exists(tableName),
                "table is not exist.tableName:{}",
                tableName);

        TableDef sourceTableDef = findDBTableDetailByTableName(tableName);
        AlterTableDDLBuilder builder = AlterTableDDLBuilderFactoryRegistry
                .getFactory(getDatabaseType())
                .newInstance(sourceTableDef);
        return builder;
    }

    /**
     * @param newTable
     * @return
     */
    @Override
    public AlterTableDDLBuilder generateAlterTableDDLBuilder(
            TableDef newTable) {
        AssertUtils.notNull(newTable, "table is null.");
        AssertUtils.notEmpty(newTable.getName(),
                "newTable.tableName is empty.");
        AssertUtils.isTrue(exists(newTable.getName()),
                "table is not exist.tableName:{}",
                newTable.getName());

        TableDef sourceTableDef = findDBTableDetailByTableName(
                newTable.getName());
        AlterTableDDLBuilder builder = AlterTableDDLBuilderFactoryRegistry
                .getFactory(getDatabaseType())
                .newInstance(newTable, sourceTableDef);
        return builder;
    }

    /**
     * @param newTable
     * @param sourceTable
     * @return
     */
    @Override
    public AlterTableDDLBuilder generateAlterTableDDLBuilder(TableDef newTable,
                                                             TableDef sourceTable) {
        AssertUtils.notNull(newTable, "table is null.");
        AssertUtils.notEmpty(newTable.getName(),
                "newTable.tableName is empty.");

        AssertUtils.notNull(sourceTable, "table is null.");
        AssertUtils.notEmpty(sourceTable.getName(),
                "sourceTable.tableName is empty.");

        AssertUtils.isTrue(
                newTable.getName()
                        .equalsIgnoreCase(sourceTable.getName()),
                "newTable.tableName:{} should equalsIgnoreCase sourceTable.tableName:{}",
                new Object[] { newTable.getName(),
                        sourceTable.getName() });

        AlterTableDDLBuilder builder = AlterTableDDLBuilderFactoryRegistry
                .getFactory(getDatabaseType())
                .newInstance(newTable, sourceTable);
        return builder;
    }

    /**
      * Drop指定表名的数据库表<br/>
      * <功能详细描述>
      * @param tableName [参数说明]
      *
      * @return void [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    @Override
    public void drop(String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");
        AssertUtils.isTrue(exists(tableName),
                "table is not exist.tableName:{}",
                tableName);

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);

        Properties props = new Properties();
        props.put("tableName", tableName);
        String dropSql = placeholderHelper.replacePlaceholders(SQL_DROP_TABLE,
                props);

        //打印删除表日志:
        StringBuilder sb = new StringBuilder(TxConstants.INITIAL_STR_LENGTH);
        sb.append("删除数据库表:").append(tableName).append("\t\n");
        sb.append("------删除表:")
                .append(tableName)
                .append("----------------------------start")
                .append("\t\n");
        sb.append(dropSql).append("\t\n");
        sb.append("------删除表:")
                .append(tableName)
                .append("------------------------------end")
                .append("\t\n");
        logger.info(sb.toString());

        this.jdbcTemplate.execute(dropSql);

        logger.info("删除数据库表:{}成功.", tableName);
    }

    /**
      * 备份表<br/>
      * <功能详细描述>
      * @param tableName
      * @param backupTableName [参数说明]
      *
      * @return void [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    @Override
    public void backup(String tableName, String backupTableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");
        AssertUtils.notEmpty(backupTableName, "backupTableName is empty.");

        AssertUtils.isTrue(exists(tableName),
                "table is not exist.tableName:{}",
                tableName);
        AssertUtils.isTrue(!exists(backupTableName),
                "backupTableName is exist.backupTableName:{}",
                backupTableName);

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);
        //根据配置变更表名
        backupTableName = getTableNameForDatabaseMetaData(backupTableName);


        Properties props = new Properties();
        props.put("tableName", tableName);
        props.put("backupTableName", backupTableName);
        String backupSql = placeholderHelper
                .replacePlaceholders(SQL_BACKUP_TABLE, props);

        //打印备份表日志:
        StringBuilder sb = new StringBuilder(TxConstants.INITIAL_STR_LENGTH);
        sb.append("备份数据库表:")
                .append(tableName)
                .append(" to ")
                .append(backupTableName)
                .append("\t\n");
        sb.append("------备份表:")
                .append(tableName)
                .append(" to ")
                .append(backupTableName)
                .append("----------------------------start")
                .append("\t\n");
        sb.append(backupSql).append("\t\n");
        sb.append("------备份表:")
                .append(tableName)
                .append(" to ")
                .append(backupTableName)
                .append("------------------------------end")
                .append("\t\n");
        logger.info(sb.toString());

        this.jdbcTemplate.execute(backupSql);

        logger.info("备份数据库表:{} to {} 成功.", tableName, backupTableName);
    }

    /**
     * 创建表<br/>
     * <功能详细描述>
     * @param builder [参数说明]
     *
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
    */
    @Override
    public void create(CreateTableDDLBuilder builder) {
        AssertUtils.notNull(builder, "builder is null.");
        AssertUtils.isTrue(!exists(builder.tableName()),
                "table is exist.tableName:{}",
                builder.tableName());
        AssertUtils.notEmpty(builder.getColumns(), "table.columns is empty.");

        //根据数据库特性设置表名
        builder.setTableName(getTableNameForDatabaseMetaData(builder.tableName()));

        String createSql = builder.createSql();
        //打印创建表日志:
        StringBuilder sb = new StringBuilder(TxConstants.INITIAL_STR_LENGTH);
        sb.append("创建数据库表:").append(builder.tableName()).append("\t\n");
        sb.append("------创建表:")
                .append(builder.tableName())
                .append("----------------------------start")
                .append("\t\n");
        sb.append(createSql).append("\t\n");
        sb.append("------创建表:")
                .append(builder.tableName())
                .append("------------------------------end")
                .append("\t\n");
        logger.info(sb.toString());

        createSql = SqlUtils.format(builder.createSql());
        String[] createSqls = StringUtils.splitByWholeSeparator(createSql, ";");
        for (String createSqlTemp : createSqls) {
            if (!StringUtils.isBlank(createSqlTemp)) {
                this.jdbcTemplate.execute(createSqlTemp);
            }
        }

        logger.info("创建数据库表: {} 成功.", builder.tableName());
    }

    /**
     * 修改表<br/>
     * <功能详细描述>
     * @param builder [参数说明]
     *
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
    */
    @Override
    public void alter(AlterTableDDLBuilder builder) {
        AssertUtils.notNull(builder, "builder is null.");
        AssertUtils.isTrue(exists(builder.tableName()),
                "table is not exist.tableName:{}",
                builder.tableName());

        //根据数据库特性设置表名
        builder.setTableName(getTableNameForDatabaseMetaData(builder.tableName()));

        String alterSql = builder.alterSql();
        if (StringUtils.isBlank(alterSql)) {
            return;
        }

        //打印修改表日志:
        StringBuilder sb = new StringBuilder(TxConstants.INITIAL_STR_LENGTH);
        sb.append("修改数据库表:").append(builder.tableName()).append("\t\n");
        sb.append("------修改表:")
                .append(builder.tableName())
                .append("----------------------------start")
                .append("\t\n");
        sb.append(alterSql).append("\t\n");
        sb.append("------修改表:")
                .append(builder.tableName())
                .append("------------------------------end")
                .append("\t\n");
        logger.info(sb.toString());

        alterSql = SqlUtils.format(alterSql);
        try {
            String[] alterSqls = StringUtils.splitByWholeSeparator(alterSql,
                    ";");
            for (String alterSqlTemp : alterSqls) {
                if (!StringUtils.isBlank(alterSqlTemp)) {
                    this.jdbcTemplate.execute(alterSqlTemp);
                }
            }

            logger.info("修改数据库表: {} 成功.", builder.tableName());
        } catch (DataAccessException e) {
            logger.error(MessageUtils.format("修改数据库表: {} 异常.异常信息:{}.",
                    builder.tableName(),
                    e.getMessage()), e);

            throw new SILException(MessageUtils.format("修改数据库表: {} 异常.异常信息:{}.",
                    builder.tableName(),
                    e.getMessage()), e);
        } catch (SILException e) {
            logger.error(MessageUtils.format("修改数据库表: {} 异常.异常信息:{}.",
                    builder.tableName(),
                    e.getMessage()), e);
            throw e;
        }
    }

    /**
     * 根据表名判断表是否存在<br/>
     * <功能详细描述>
     * @param tableName
     * @return [参数说明]
     *
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Override
    public boolean exists(String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);

        try(Connection conn = this.dataSource.getConnection()){
            DatabaseMetaData dbmd = conn.getMetaData();
            ResultSet rs = dbmd.getTables(catalog, "%", tableName, new String[]{"TABLE"});
            if(rs.next()){
                return true;
            }else{
                return false;
            }
        } catch (SQLException e) {
            throw new SILException("判断表是否存在出现异常.",e);
        }
    }

    /**
     * 从当前数据库中获取当前表定义<br/>
     * <功能详细描述>
     * @param tableName
     * @return [参数说明]
     *
     * @return DDLTable [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
    */
    @Override
    public DBTableDef findDBTableDetailByTableName(String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);

        try (Connection con = this.dataSource.getConnection();) {
            DatabaseMetaData dbmd = con.getMetaData();
            String schema = con.getSchema();
            String catalog = con.getCatalog();

            DBTableDef dbTableDef = new DBTableDef();
            dbTableDef.setName(tableName);
            dbTableDef.setSchema(schema);
            dbTableDef.setCatalog(catalog);
            ResultSet rs = dbmd.getTables(catalog, "%", tableName, new String[]{"TABLE"});
            if (rs.next()) {
                String comment = rs.getString("REMARKS");
                //System.out.println("REMARKS:" + comment);
                dbTableDef.setComment(comment);

                //获取主键
                List<DBTableDef.DBTablePrimaryKey> pks = getPrimaryKeys(dbmd, dbTableDef);
                dbTableDef.setPrimaryKeyList(pks);
                //System.out.println("primaryKeys:" + dbTableDef.getPrimaryKey());

                List<DBColumnDef> columns = getColumns(catalog,"%", tableName, dbmd);
                List<DBIndexDef> indexes = getIndexes(catalog, schema, tableName,dbmd);
                dbTableDef.setColumns(columns);
                dbTableDef.setIndexes(indexes);

                return dbTableDef;
            }else{
                return null;
            }
        } catch (SQLException e) {
            throw new SILException("获取表索引出现异常.",e);
        }
    }

    /**
      * 根据表名查询DDL的字段集合<br/>
      * <功能详细描述>
      * @param tableName
      * @return [参数说明]
      *
      * @return List<DDLColumn> [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    @Override
    public List<DBColumnDef> queryDBColumnsByTableName(String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);

        try(Connection conn = this.dataSource.getConnection()){
            DatabaseMetaData dbmd = conn.getMetaData();
            List<DBColumnDef> ddlColumnList = getColumns(conn.getCatalog(),"%", tableName, dbmd);
            return ddlColumnList;
        } catch (SQLException e) {
            throw new SILException("获取表字段出现异常.",e);
        }
    }

    /**
      * 根据表名查询DDL的索引集合<br/>
      * <功能详细描述>
      * @param tableName
      * @return [参数说明]
      *
      * @return List<DDLIndex> [返回类型说明]
      * @exception throws [异常类型] [异常说明]
      * @see [类、类#方法、类#成员]
     */
    @Override
    public List<DBIndexDef> queryDBIndexesByTableName(String tableName) {
        AssertUtils.notEmpty(tableName, "tableName is empty.");

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);

        try(Connection conn = this.dataSource.getConnection()){
            DatabaseMetaData dbmd = conn.getMetaData();

            List<DBIndexDef> ddlIndexList = getIndexes(conn.getCatalog(),conn.getSchema(),tableName,dbmd);
            return ddlIndexList;
        } catch (SQLException e) {
            throw new SILException("获取表索引出现异常.",e);
        }
    }

    /**
     * 获取表主键<br/>
     * @param metaData
     * @param table
     * @return
     * @throws SQLException
     */
    private List<DBTableDef.DBTablePrimaryKey> getPrimaryKeys(DatabaseMetaData metaData, TableDef table) throws SQLException{
        List<DBTableDef.DBTablePrimaryKey> list = new ArrayList<>();
        if (metaData == null) {
            return list;
        }

        ResultSet primaryKeys = metaData.getPrimaryKeys(table.getCatalog(), table.getSchema(), getTableNameForDatabaseMetaData(table.getName()));
        while (primaryKeys.next()) {
            String columnName = primaryKeys.getString("COLUMN_NAME");
            int keySeq = primaryKeys.getInt("KEY_SEQ");
            String pkName = primaryKeys.getString("PK_NAME");
            list.add(new DBTableDef.DBTablePrimaryKey(table.getName(), pkName, columnName, keySeq));
        }
        return list;
    }

    /**
     * 从connect中获取表字段
     * @param catalog
     * @param schemaPattern
     * @param tableName
     * @param metaData
     * @return
     * @throws SQLException
     */
    private List<DBColumnDef> getColumns(String catalog,String schemaPattern,String tableName,DatabaseMetaData metaData) throws SQLException {
        List<DBColumnDef> list = new ArrayList<>();
        if (metaData == null) {
            return list;
        }

        //根据配置变更表名
        tableName = getTableNameForDatabaseMetaData(tableName);

        ResultSet columns = metaData.getColumns(catalog, schemaPattern, tableName, "%");
        while (columns.next()) {
            String columnName = columns.getString("COLUMN_NAME");
            String columnType = columns.getString("TYPE_NAME");
            int dataSize = columns.getInt("COLUMN_SIZE");
            int digits = columns.getInt("DECIMAL_DIGITS");
            boolean nullable = columns.getBoolean("NULLABLE");
            boolean autoIncrement = columns.getBoolean("IS_AUTOINCREMENT");
            String defaultValue = columns.getString("COLUMN_DEF");
            int ordinalPosition = columns.getInt("ORDINAL_POSITION");
            if (defaultValue == null) {
                defaultValue = "";
            }
            String comment = columns.getString("REMARKS");

            DBColumnDef c = new DBColumnDef();
            c.setTableName(tableName);
            c.setPriority(ordinalPosition);
            c.setComment(comment);
            c.setColumnName(columnName);
            c.setRequired(!nullable);
            c.setDefaultValue(defaultValue);
            JdbcTypeEnum jdbcType = JdbcTypeEnum.forTypeKey(columnType);
            if(jdbcType == null){
                this.logger.warn("jdbcType is null.tableName:{} columnName:{} columnType:{}",tableName,columnName,columnType);
            }
            c.setJdbcType(jdbcType);
            c.setSize(dataSize);
            c.setScale(digits);
            list.add(c);
        }
        return list;
    }

    /**
     * 从connection中的metaData中获取表结构
     * @param catalog
     * @param schema
     * @param tableName
     * @param metaData
     * @return
     * @throws SQLException
     */
    private List<DBIndexDef> getIndexes(String catalog, String schema, String tableName, DatabaseMetaData metaData) throws SQLException{
        List<DBIndexDef> list = new ArrayList<>();
        if (metaData == null) {
            return list;
        }

        //根据配置变更表名
        final String newTableName = getTableNameForDatabaseMetaData(tableName);

        MultiValueMap<String, DBIndexDef.DBIndexColumnDef> map = new LinkedMultiValueMap<>(16);
        //Map<String, TableIndexDef> map = new HashMap<>(16);
        ResultSet indexInfo = metaData.getIndexInfo(catalog, schema, newTableName, false, false);
        while (indexInfo.next()) {
            String indexName = indexInfo.getString("INDEX_NAME");
            String columnName = indexInfo.getString("COLUMN_NAME");
            boolean unique = !indexInfo.getBoolean("NON_UNIQUE");
            Short ordinalPosition = indexInfo.getShort("ORDINAL_POSITION");
            if(StringUtils.equalsIgnoreCase("PRIMARY",indexName)){
                //mybatis
                continue;
            }
            if(StringUtils.startsWithIgnoreCase(indexName,"PRIMARY_KEY_")){
                continue;
            }
            if(StringUtils.equalsIgnoreCase(indexName,tableName + "_pkey")){
                continue;
            }

            DBIndexDef.DBIndexColumnDef row = new DBIndexDef.DBIndexColumnDef();
            row.setIndexName(indexName);
            row.setColumnName(columnName);
            row.setUnique(unique);
            row.setOrdinalPosition(ordinalPosition);

            map.add(indexName,row);
        }

        map.forEach((indexName, rowList) -> {
            DBIndexDef c = new DBIndexDef();
            c.setTableName(newTableName);
            c.setColumnNames(rowList.stream().filter(p -> {
                return p != null;
            }).sorted((p1, p2) -> {
                Short ps1 = p1.getOrdinalPosition();
                Short ps2 = p2.getOrdinalPosition();
                return ps1.compareTo(ps2);
            }).map(pk -> pk.getColumnName()).collect(Collectors.joining(",")));
            c.setUnique(rowList.get(0).isUnique());
            c.setName(rowList.get(0).getIndexName());

            list.add(c);
        });
        return list;
    }

    /**
     * 是否将表名大写
     * @return
     */
    protected boolean isToUpperCaseOfTableNameForGetTableMetaData(){
        return false;
    }

    /**
     * 是否将表名小写
     * @return
     */
    protected boolean isToLowerCaseOfTableNameForGetTableMetaData(){
        return false;
    }

    /**
     * 获取能从数据库中取出表信息的表名
     *    三种情况： 不作变化、大写、小写
     * @param tableName
     * @return
     */
    private String getTableNameForDatabaseMetaData(String tableName){
        AssertUtils.notEmpty(tableName,"tableName is empty.");
        if(isToUpperCaseOfTableNameForGetTableMetaData()){
            return tableName.toUpperCase();
        }
        if(isToLowerCaseOfTableNameForGetTableMetaData()){
            return tableName.toLowerCase();
        }
        return tableName;
    }

    /**
     * 设置数据源<br/>
     * @param dataSource
     */
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}
